﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Brio.Framework.Operators
{
    class CrossoverOperator : MusicalOperator
    {
        public CrossoverOperator(int percentage) : base("Crossover", percentage, OperatorType.Diploid) { }

        public override void Apply(MotifChromosome chromo1, MotifChromosome chromo2)
        {
            // Create a mapping of the staff indexes to rhythm indexes
            Dictionary<int, int> staffToRhythm = new Dictionary<int, int>();
            for (int i = 0; i < chromo1.Staff.Rhythm.Length; i++)
            {
                staffToRhythm.Add(chromo1.Staff.GetStaffIndexFromRhythmIndex(i), i);
            }

            int rhythmPoint1, staffPoint1, actualPoint;

            // Generate a random number no larger than the size of Rhythm
            rhythmPoint1 = Constants.Random.Next(chromo1.Staff.Rhythm.Length);
            staffPoint1 = chromo1.Staff.GetStaffIndexFromRhythmIndex(rhythmPoint1);
            actualPoint = -1;

            // Loop through the rhythm indices and see if the separation between two notes exists in the same place for both chromosomes
            // If so, use that as actual crossover point
            // If not, start looking forward and backward to find a consistent separation
            for (int i = 0; i < chromo1.Staff.Rhythm.Length; i++)
            {
                if (rhythmPoint1 - i >= 0 && staffToRhythm.ContainsKey(chromo1.Staff.GetStaffIndexFromRhythmIndex(rhythmPoint1 - i)))
                {
                    actualPoint = chromo1.Staff.GetStaffIndexFromRhythmIndex(rhythmPoint1 - i);
                }
                else if (rhythmPoint1 + i < chromo1.Staff.Rhythm.Length && staffToRhythm.ContainsKey(chromo1.Staff.GetStaffIndexFromRhythmIndex(rhythmPoint1 + i)))
                {
                    actualPoint = chromo1.Staff.GetStaffIndexFromRhythmIndex(rhythmPoint1 + i);
                }
            }

            // Not interested in -1 or 0, only perform crossover where it matters
            if (actualPoint != -1 && actualPoint != 0)
            {
                // Use single point crossover
                chromo1.Staff.Crossover(chromo2, actualPoint, "LHS");
                chromo2.Staff.Crossover(chromo1, actualPoint, "RHS");
            }
        }

        public override void Apply(MotifChromosome chromo) 
        { 
            // UNSUPPORTED
        }

        public override void Apply(MotifChromosome chromo, IntervalRelationshipTable intervalRelationships)
        {
            // UNSUPPORTED
        }

        public override void Apply(MotifChromosome chromo, TechniqueCollection techniqueCollection)
        {
            // UNSUPPORTED
        }
    }
}
